package com.opages.mvc.adapter.common.condition;

import com.opages.mvc.adapter.common.condition.annotation.ConditionalOnBean;
import com.opages.mvc.adapter.common.autoconfigure.AutoConfigurationMetadata;
import com.opages.mvc.adapter.common.condition.core.ConditionOutcome;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * srping容器中bean存在则返回真,表示可以注入
 * @author daizhong.liu
 * @create 2020-07-02 14:06
 **/
public class OnBeanCondition extends FilteringCondition implements ConfigurationCondition {
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnBean.class.getName());
        Class[] classes = (Class[])annotationAttributes.get("value");
        List<Class> clazzs = new ArrayList<>();
        if(classes != null || classes.length > 0) {
            clazzs.addAll(Arrays.asList(classes));
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            boolean isMatch = true;
            try {
                if (beanFactory != null) {
                    for (Class clazz : clazzs) {
                        Object bean = context.getBeanFactory().getBean(clazz);
                    }
                    return ConditionOutcome.match();
                }
            }catch (NoSuchBeanDefinitionException e){}
        }
        return ConditionOutcome.noMatch();

    }

    @Override
    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.REGISTER_BEAN;
    }
    //用于自动配置时的条件判断
    @Override
    protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
        for (int i = 0; i < outcomes.length; i++) {
            //OnBeanCondition、OnClassCondition两种过滤器
            String autoConfigurationClass = autoConfigurationClasses[i];
            if (autoConfigurationClass != null) {
                //如果依赖包有配置xxxAutoConfigrution.ConditionalOnBean=beanTypes，父类filter中要求null或Match，说明需要匹配出missing的，即不存在则为Match
                Set<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");
                outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
                if (outcomes[i] == null) {
                    outcomes[i] = ConditionOutcome.match();
                }
            }
        }
        return outcomes;
    }
    //容器中存在指定Bean才生效，因此如果MISSING有数据，则表示找不到指定Bean，那不匹配
    private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
        //MISSING表示不存在，有不存在的Bean集合时就表示noMatch()
        List<String> exist = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());
        //不为空，表示有不存在的Bean集合
        if (!exist.isEmpty()) {
            return ConditionOutcome.noMatch();
        }
        return null;
    }
}
